library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity fsm is
	port (
		--inputs
		clk : in std_logic;
		reset : in std_logic;
		i_read : in std_logic;
		i_readdata : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		fault_0 : in std_logic;
		fault_1 : in std_logic;
		fault_2 : in std_logic;
		valid : in std_logic;
		
		--outputs
		sel_0 : out std_logic_vector (1 downto 0);
		sel_1 : out std_logic_vector (1 downto 0);
		sel_2 : out std_logic_vector (1 downto 0);
		validation_sel : out std_logic_vector (1 downto 0);
		validation_enable : out std_logic;
		sel_mux_break : out std_logic_vector (1 downto 0);
		reset_0 : out std_logic;
		reset_1 : out std_logic;
		reset_2 : out std_logic;
		reset_3 : out std_logic;
		leds : out std_logic_vector (7 downto 0)
	);
end entity;

architecture behavioral of fsm is
type t_state is (RESET_FIRST_PART, RESET_SECOND_PART, NORMAL, RET_FROM_RESET_P0, RET_FROM_RESET_P1, RET_FROM_RESET_P2, BREAK_P0, BREAK_P1, BREAK_P2, VAL_P0, VAL_P1, VAL_P2, BROKEN_P0, BROKEN_P1, BROKEN_P2, OUT_OF_SERVICE);

signal state : t_state;
signal counter_start_long : std_logic;
signal counter_finish_long : std_logic;
signal counter_long : natural;
signal counter_start_short : std_logic;
signal counter_finish_short : std_logic;
signal counter_short : natural;
signal counter_1 : natural;
signal break_request : std_logic;
signal break_complete : std_logic;


begin

	the_fsm : process (reset, clk)
	begin
		if reset = '0' then
			state <= RESET_FIRST_PART;
			counter_start_long <= '0';
			counter_start_short <= '0';
			validation_enable <= '0';
			sel_0 <= "00";
			sel_1 <= "01";
			sel_2 <= "10";
			validation_sel <= "00";

			break_request <= '0';
			reset_0 <= '1';
			reset_1 <= '1';
			reset_2 <= '1';
			reset_3 <= '1';
			leds <= "01011010";
		elsif clk'event and clk = '1' then
			case state is
				when RESET_FIRST_PART =>
					if counter_finish_long = '1' then
						state <= RESET_SECOND_PART;
					else
						state <= RESET_FIRST_PART;
					end if;
					counter_start_long <= '1';
					counter_start_short <= '0';
					validation_enable <= '0';
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";

					break_request <= '0';
					reset_0 <= '1';
					reset_1 <= '1';
					reset_2 <= '1';
					reset_3 <= '1';
					leds <= "01011010";
					
				when RESET_SECOND_PART =>
					if counter_finish_short = '1' then
						state <= RESET_SECOND_PART;
					else
						state <= NORMAL;
					end if;
					counter_start_long <= '0';
					counter_start_short <= '1';
					validation_enable <= '0';
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";

					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '1';
					leds <= "01011010";
					
				when NORMAL =>
					if fault_0 = '1' and fault_1 = '0' and fault_2 = '0' then
						state <= RET_FROM_RESET_P0;
					else
						if fault_0 = '0' and fault_1 = '1' and fault_2 = '0' then
							state <= RET_FROM_RESET_P1;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '1' then
								state <= RET_FROM_RESET_P2;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' then
									state <= NORMAL;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '0';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '1';
					leds <= "11111100";

				when RET_FROM_RESET_P0 =>
					if counter_finish_short = '0' then
						state <= RET_FROM_RESET_P0;
					else
						state <= BREAK_P0;
					end if;
							 
					counter_start_long <= '0';
					counter_start_short <= '1';
					validation_enable <= '0';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "01111111";
					
				when RET_FROM_RESET_P1 =>
					if counter_finish_short = '0' then
						state <= RET_FROM_RESET_P1;
					else
						state <= BREAK_P1;
					end if;
							 
					counter_start_long <= '0';
					counter_start_short <= '1';
					validation_enable <= '0';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11011111";
					
				when RET_FROM_RESET_P2 =>
					if counter_finish_short = '0' then
						state <= RET_FROM_RESET_P2;
					else
						state <= BREAK_P2;
					end if;
							 
					counter_start_long <= '0';
					counter_start_short <= '1';
					validation_enable <= '0';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11110111";
					
				when BREAK_P0 =>
					if break_complete = '0' then
						state <= BREAK_P0;
					elsif break_complete = '1' then
						state <= VAL_P0;
					else
						state <= OUT_OF_SERVICE;
					end if;
							 
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '1';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '1';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "01111111";
				when BREAK_P1 =>
					if break_complete = '0' then
						state <= BREAK_P1;
					elsif break_complete = '1' then
						state <= VAL_P1;
					else
						state <= OUT_OF_SERVICE;
					end if;

					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '1';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "01";
					
					break_request <= '1';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11011111";
				when BREAK_P2 =>
					if break_complete = '0' then
						state <= BREAK_P2;
					elsif break_complete = '1' then
						state <= VAL_P2;
					else
						state <= OUT_OF_SERVICE;
					end if;
					
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '1';
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "10";
					
					break_request <= '1';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11110111";
				when VAL_P0 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' then 
						state <= NORMAL;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' then 
							state <= VAL_P0;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' then 
								state <= BROKEN_P0;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' then 
									state <= BROKEN_P0;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
					counter_start_long <= '1';
					counter_start_short <= '0';
					validation_enable <= '1';

					
					sel_0 <= "11";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
	                leds <= "10111111";	
				when VAL_P1 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' then 
						state <= NORMAL;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' then 
							state <= VAL_P1;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' then 
								state <= BROKEN_P1;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' then 
									state <= BROKEN_P1;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;

					counter_start_long <= '1';
					counter_start_short <= '0';
					validation_enable <= '1';

					
					sel_0 <= "00";
					sel_1 <= "11";
					sel_2 <= "10";
					validation_sel <= "01";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11101111";
				when VAL_P2 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' then 
						state <= NORMAL;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' then 
							state <= VAL_P2;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' then 
								state <= BROKEN_P2;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' then 
									state <= BROKEN_P2;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
					
					counter_start_long <= '1';
					counter_start_short <= '0';
					validation_enable <= '1';

					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "11";
					validation_sel <= "10";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11111011";
				when BROKEN_P0 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' and break_complete = '0' then 
						state <= BROKEN_P0;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' and break_complete = '0' then 
							state <= BROKEN_P0;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' and break_complete = '0' then 
								state <= BROKEN_P0;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' and break_complete = '0' then 
									state <= BROKEN_P0;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
							 
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '0';

					
					sel_0 <= "11";
					sel_1 <= "01";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '1';
					reset_1 <= '0';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "00111111";
				when BROKEN_P1 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' and break_complete = '0' then 
						state <= BROKEN_P1;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' and break_complete = '0' then 
							state <= BROKEN_P1;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' and break_complete = '0' then 
								state <= BROKEN_P1;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' and break_complete = '0' then 
									state <= BROKEN_P1;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
					
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '0';

					
					sel_0 <= "00";
					sel_1 <= "11";
					sel_2 <= "10";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '1';
					reset_2 <= '0';
					reset_3 <= '0';
					leds <= "11001111";
				when BROKEN_P2 =>
					if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '0' and break_complete = '0' then 
						state <= BROKEN_P2;
					else
						if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '0' and counter_finish_long = '1' and break_complete = '0' then 
							state <= BROKEN_P2;
						else
							if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '0' and break_complete = '0' then 
								state <= BROKEN_P2;
							else
								if fault_0 = '0' and fault_1 = '0' and fault_2 = '0' and valid = '1' and counter_finish_long = '1' and break_complete = '0' then 
									state <= BROKEN_P2;
								else
									state <= OUT_OF_SERVICE;
								end if;
							end if;
						end if;
					end if;
					
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '0';
					
					
					sel_0 <= "00";
					sel_1 <= "01";
					sel_2 <= "11";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '0';
					reset_1 <= '0';
					reset_2 <= '1';
					reset_3 <= '0';
					leds <= "11110011";
				when OUT_OF_SERVICE =>
					state <= OUT_OF_SERVICE;
					counter_start_long <= '0';
					counter_start_short <= '0';
					validation_enable <= '0';

					
					sel_0 <= "00";
					sel_1 <= "00";
					sel_2 <= "00";
					validation_sel <= "00";
					
					break_request <= '0';
					reset_0 <= '1';
					reset_1 <= '1';
					reset_2 <= '1';
					reset_3 <= '1';
					leds <= "00000000";
			end case;
		end if;
	end process;
	
	the_counter_long : process (reset, clk)
	begin
		if reset = '0' then
			counter_finish_long <= '0';
			counter_long <= 0;
		elsif clk'event and clk = '1' then
			if counter_long = 50000000 then
				counter_finish_long <= '1';
				counter_long <= 0;
			elsif counter_start_long = '1' then
				counter_finish_long <= '0';
				counter_long <= counter_long +1;
			else
				counter_finish_long <= '0';
				counter_long <= 0;
			end if;
		end if;
	end process;
	
	the_counter_short : process (reset, clk)
	begin
		if reset = '0' then
			counter_finish_short <= '0';
			counter_short <= 0;
		elsif clk'event and clk = '1' then
			if counter_short = 1000 then
				counter_finish_short <= '1';
				counter_short <= 0;
			elsif counter_start_short = '1' then
				counter_finish_short <= '0';
				counter_short <= counter_short +1;
			else
				counter_finish_short <= '0';
				counter_short <= 0;
			end if;
		end if;
	end process;

	the_breaker : process (reset, clk)
	begin
		if reset = '0' then
			break_complete <= '0';
			sel_mux_break <= "00";
			counter_1 <= 0;
			
		elsif clk'event and clk = '1' then
			if counter_1 > 0 then
				if counter_1 = 11 then
					if i_readdata = "11110000000000000100100000111010" then
						break_complete <= '1';
						sel_mux_break <= "00";
						counter_1 <= 0;
					else
						break_complete <= '0';
						sel_mux_break <= "00";
						counter_1 <= counter_1;
					end if;
				else
					if counter_1 = 10 then
						break_complete <= '0';
						sel_mux_break <= "01";
						counter_1 <= counter_1 + 1;
					else
						if counter_1 = 6 then
							break_complete <= '0';
							sel_mux_break <= "01";
							counter_1 <= counter_1 + 1;
						else
							if counter_1 = 5 then
								break_complete <= '0';
								sel_mux_break <= "10";
								counter_1 <= counter_1 + 1;
							else
								break_complete <= '0';
								sel_mux_break <= "00";
								counter_1 <= counter_1 + 1;
							end if;
						end if;
					end if;
				end if;
			else
				if break_request = '1' then
					if i_read = '1' then
						counter_1 <= 1;
						break_complete <= '0';
						sel_mux_break <= "10";
					else
						counter_1 <= 0;
						break_complete <= '0';
						sel_mux_break <= "00";
					end if;
				else
					counter_1 <= 0;
					break_complete <= '0';
					sel_mux_break <= "00";
				end if;
			end if;
		end if;
	end process;
end behavioral;
